#include "debug.h"
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include "Utils\\ResGroupManager.h"
#include "Elements\\PushButton.h"

using namespace SDL::UTILS;

NS_BEGIN(SDL)
NS_BEGIN(ELEMENTS)

Surface* PushButton::IMG_RELEASED = NULL;
Surface* PushButton::IMG_HOVERED = NULL;
Surface* PushButton::IMG_PRESSED = NULL;
Surface* PushButton::IMG_CLICKED = NULL;
Surface* PushButton::IMG_DISABLED = NULL;

SDL_Rect PushButton::Rects::UpperLeft = {0, 0, 14, 14};
SDL_Rect PushButton::Rects::Upper = {14, 0, 4, 14};
SDL_Rect PushButton::Rects::UpperRight = {18, 0, 14, 14};
SDL_Rect PushButton::Rects::Right = {18, 14, 14, 4};
SDL_Rect PushButton::Rects::BottomRight = {18, 18, 14, 14};
SDL_Rect PushButton::Rects::Bottom = {14, 18, 4, 14};
SDL_Rect PushButton::Rects::BottomLeft = {0, 18, 14, 14};
SDL_Rect PushButton::Rects::Left = {0, 14, 14, 4};
SDL_Rect PushButton::Rects::Center = {14, 14, 4, 4};

#pragma region PushButton::Rects

PushButton::Rects::Rects() {}
PushButton::Rects::~Rects() {}

void PushButton::Rects::InitSurfaces(std::vector<UTILS::Surface*> const& _srcs,
									std::vector<UTILS::Surface*> const& _dsts,
									Rect const& _size, std::wstring const& _text,
									Font const& _font)
{
	if (_srcs.size() != _dsts.size())
		return ;

	Rect size(_size);
	if (size.GetW() < 32)
		size.SetW(32);
	if (size.GetH() < 32)
		size.SetH(32);

	int w = 0, h = 0, wtotal = 0, htotal = 0;
	TTF_SizeText(_font.GetFont(), Font::WStringToString(_text).c_str(), &w, &h);
	if (w > size.GetW())
	{
		int w2 = 0;
		for (; w2 < w; w2 += Center.w);
		w = w2;
		size.SetW(w2);
	}
	if (h > size.GetH())
	{
		int h2 = 0;
		for (; h2 < h; h2 += Center.h);
		h = h2;
		size.SetH(h2);
	}

	wtotal = size.GetW();
	htotal = size.GetH();

	for (int m = 0; m < _dsts.size(); m++)
		_dsts[m]->SetSurface(
			SDL_CreateRGBSurface(SDL_HWSURFACE, wtotal, htotal, 32, 0, 0, 0, 0));
	SDL_Rect rect = {0, 0, 0, 0};

	w = wtotal - (UpperLeft.w + UpperRight.w);
	h = htotal - (UpperLeft.h + BottomLeft.h);
	
	rect.y = 0;
	rect.w = Upper.w;
	rect.h = Upper.h;
	for (int i = 0; i < w; i += Center.w)
	{
		rect.x = UpperLeft.w + i;
		for (int k = 0, m = 0; k < _dsts.size(); k++, m++)
			SDL_BlitSurface(_srcs[k]->GetSurface(), &Upper,
							_dsts[m]->GetSurface(), &rect);
	}
	
	rect.w = Bottom.w;
	rect.h = Bottom.h;
	rect.y = htotal - Bottom.h;
	for (int i = 0; i < w; i += Center.w)
	{
		rect.x = UpperLeft.w + i;
		for (int k = 0, m = 0; k < _dsts.size(); k++, m++)
			SDL_BlitSurface(_srcs[k]->GetSurface(), &Bottom,
							_dsts[m]->GetSurface(), &rect);
	}

	rect.w = Left.w;
	rect.h = Left.h;
	rect.x = 0;
	for (int i = 0; i < h; i += Center.h)
	{
		rect.y = UpperLeft.h + i;
		for (int k = 0, m = 0; k < _dsts.size(); k++, m++)
			SDL_BlitSurface(_srcs[k]->GetSurface(), &Left,
							_dsts[m]->GetSurface(), &rect);
	}

	rect.w = Right.w;
	rect.h = Right.h;
	rect.x = wtotal - Right.w;
	for (int i = 0; i < h; i += Center.h)
	{
		rect.y = UpperLeft.h + i;
		for (int k = 0, m = 0; k < _dsts.size(); k++, m++)
			SDL_BlitSurface(_srcs[k]->GetSurface(), &Right,
							_dsts[m]->GetSurface(), &rect);
	}

	rect.w = Center.w;
	rect.h = Center.h;
	for (int i = 0; i < h; i += Center.h)
	{
		rect.y = UpperLeft.h + i;
		for (int j = 0; j < w; j += Center.w)
		{
			rect.x = UpperLeft.w + j;
			for (int k = 0, m = 0; k < _dsts.size(); k++, m++)
				SDL_BlitSurface(_srcs[k]->GetSurface(), &Center,
								_dsts[m]->GetSurface(), &rect);
		}
	}

	for (int k = 0, m = 0; k < _dsts.size(); k++, m++)
	{
		rect.x = 0;
		rect.y = 0;
		rect.w = UpperLeft.w;
		rect.h = UpperLeft.h;
		SDL_BlitSurface(_srcs[k]->GetSurface(), &UpperLeft,
						_dsts[m]->GetSurface(), &rect);

		rect.x = wtotal - UpperRight.w;
		rect.y = 0;
		rect.w = UpperRight.w;
		rect.h = UpperRight.h;
		SDL_BlitSurface(_srcs[k]->GetSurface(), &UpperRight,
						_dsts[m]->GetSurface(), &rect);

		rect.x = wtotal - BottomRight.w;
		rect.y = htotal - BottomRight.h;
		rect.w = BottomRight.w;
		rect.h = BottomRight.h;
		SDL_BlitSurface(_srcs[k]->GetSurface(), &BottomRight,
						_dsts[m]->GetSurface(), &rect);

		rect.x = 0;
		rect.y = htotal - BottomRight.h;
		rect.w = BottomLeft.w;
		rect.h = BottomLeft.h;
		SDL_BlitSurface(_srcs[k]->GetSurface(), &BottomLeft,
							_dsts[m]->GetSurface(), &rect);

		_dsts[m]->SetColorKey(0xFF00FF);
	}
}

#pragma endregion

void PushButton::InitImages(Rect const& _size)
{
	SDL_Surface* s = NULL;
	std::wstring text = m_text.GetText();

	std::vector<Surface*> srcs, dsts;

	srcs.push_back(IMG_RELEASED);
	srcs.push_back(IMG_HOVERED);
	srcs.push_back(IMG_PRESSED);
	srcs.push_back(IMG_CLICKED);
	srcs.push_back(IMG_DISABLED);

	if (m_imgReleased != NULL) delete m_imgReleased;
	m_imgReleased = new Surface;
	if (m_imgHovered != NULL) delete m_imgHovered;
	m_imgHovered = new Surface;
	if (m_imgPressed != NULL) delete m_imgPressed;
	m_imgPressed = new Surface;
	if (m_imgClicked != NULL) delete m_imgClicked;
	m_imgClicked = new Surface;
	if (m_imgDisabled != NULL) delete m_imgDisabled;
	m_imgDisabled = new Surface;

	dsts.push_back(m_imgReleased);
	dsts.push_back(m_imgHovered);
	dsts.push_back(m_imgPressed);
	dsts.push_back(m_imgClicked);
	dsts.push_back(m_imgDisabled);

	Rects::InitSurfaces(srcs, dsts, _size, m_text.GetText(), *GetFont());
}

#pragma region CTOR & DTOR

PushButton::PushButton(std::wstring const& _text, Rect const& _defaultSize)
	: AButton(_text), m_defaultSize(_defaultSize)
{
	CTOR("PushButton", this);

	if (PushButton::IMG_RELEASED == NULL)
	{
		PushButton::IMG_RELEASED = new Surface(
			IMG_Load((*m_resGroup)["PushButton_released"]->Path.c_str()), true);
		PushButton::IMG_HOVERED = new Surface(
			IMG_Load((*m_resGroup)["PushButton_hovered"]->Path.c_str()), true);
		PushButton::IMG_PRESSED = new Surface(
			IMG_Load((*m_resGroup)["PushButton_pressed"]->Path.c_str()), true);
		PushButton::IMG_CLICKED = new Surface(
			IMG_Load((*m_resGroup)["PushButton_clicked"]->Path.c_str()), true);
		PushButton::IMG_DISABLED = new Surface(
			IMG_Load((*m_resGroup)["PushButton_disabled"]->Path.c_str()), true);
	}

	this->InitImages(m_defaultSize);

	m_surface = m_imgReleased;
	this->SetPosition(m_position.GetX(), m_position.GetY());
}

PushButton::PushButton(PushButton const& _pushButton)
	: AButton(*((AButton*)&_pushButton))
{
	CTOR("PushButton", this);
	*this = _pushButton;
}

PushButton::~PushButton()
{
	DTOR("PushButton", this);
	m_surface = NULL;
	if (m_imgReleased != NULL) delete m_imgReleased;
	if (m_imgHovered != NULL) delete m_imgHovered;
	if (m_imgPressed != NULL) delete m_imgPressed;
	if (m_imgClicked != NULL) delete m_imgClicked;
}

#pragma endregion
#pragma region Operators

PushButton& PushButton::operator=(PushButton const& _pushButton)
{
	if (this != &_pushButton)
	{
		*((AButton*)this) = *((AButton*)&_pushButton);
		m_defaultSize = _pushButton.m_defaultSize;
	}
	return (*this);
}

#pragma endregion

void PushButton::UpdateState()
{
	if (m_surface == NULL)
		return ;

	if (m_disabled == true)
	{
		m_surface = m_imgDisabled;
		return ;
	}

	int x = 0, y = 0;
	Uint8 button = SDL_GetMouseState(&x, &y);
	Rect mouse(x, y);
	Rect rSurface(m_position.GetX(), m_position.GetY(),
				 m_surface->GetW(), m_surface->GetH());

	if (Rect::IsInArea(mouse, rSurface))
	{
		if (button & SDL_BUTTON_LMASK)
		{
			m_state = BUTTON::STATE::PRESSED;
			m_surface = m_imgPressed;
		}
		else
		{
			if (m_state == BUTTON::STATE::PRESSED)
			{
				m_state = BUTTON::STATE::CLICKED;
				m_surface = m_imgClicked;
			}
			else
			{
				m_state = BUTTON::STATE::HOVERED;
				m_surface = m_imgHovered;
			}
		}
	}
	else
	{
		m_state = BUTTON::STATE::RELEASED;
		m_surface = m_imgReleased;
	}
	
}

bool PushButton::Draw(SDL_Surface* _screen)
{
	if (m_hidden == false)
	{
		if (m_surface != NULL)
			m_surface->BlitSurface(NULL, _screen, &m_position);
		else
			return (false);
		m_text.GetSurface()->BlitSurface(NULL, _screen, &m_text.GetPosition());
	}
	return (true);
}

void PushButton::SetPosition(Sint16 _x, Sint16 _y)
{
	if (m_surface == NULL)
		return ;

	m_position.x = _x;
	m_position.y = _y;
	Rect textPos;

	textPos.SetX(_x + (m_surface->GetW() / 2 - m_text.GetSurface()->GetW() / 2));
	textPos.SetY(_y + (m_surface->GetH() / 2 - m_text.GetSurface()->GetH() / 2));

	m_text.SetPosition(textPos);
}

void PushButton::SetPosition(Rect const& _position)
{
	this->SetPosition(_position.GetX(), _position.GetY());
}

void PushButton::Move(Sint16 _offsetX, Sint16 _offsetY)
{
	m_position.SetX(m_position.GetX() + _offsetX);
	m_position.SetY(m_position.GetY() + _offsetY);
	m_text.Move(_offsetX, _offsetY);
}

void PushButton::Move(Rect const& _offset)
{
	this->Move(_offset.GetX(), _offset.GetY());
}

#pragma region Getters & Setter

Rect const& PushButton::GetDefaultSize() const
{
	return (m_defaultSize);
}

void PushButton::SetDefaultSize(Rect const& _defaultSize)
{
	m_defaultSize = _defaultSize;
	this->InitImages(m_defaultSize);
	this->SetPosition(m_position.GetX(), m_position.GetY());
}

void PushButton::SetText(std::wstring const& _text)
{
	m_text.Render(_text, Font::RenderBlended);

	if ((m_defaultSize.GetW() == 0 || m_defaultSize.GetH() == 0) ||
		m_text.GetSurface()->h >= m_surface->GetH() ||
		m_text.GetSurface()->w >= m_surface->GetW() ||
		m_surface->GetW() != m_defaultSize.GetW() ||
		m_surface->GetH() != m_defaultSize.GetH())
	{
		m_surface = NULL;
		this->InitImages(m_defaultSize);
		m_surface = m_imgReleased;
	}
	this->SetPosition(m_position.GetX(), m_position.GetY());
}

#pragma endregion

NS_END(ELEMENTS)
NS_END(SDL)